export class ListExposureDurationHander {
    constructor(listContainerElement, boundaryElement, reportParamObj) {
      this.$parent = listContainerElement;
      this.$boundaryElement = boundaryElement;
      this.firstShowIndex = -1;
      this.lastShowIndex = -1;
      this.exposeListData = [];
      this.eventId = reportParamObj.eventId;
      this.eventDesc = reportParamObj.eventDesc;
      this.reportHander = reportParamObj.hander;
    }
  
    // 重置曝光范围
    restoreShowIndex() {
      this.firstShowIndex = -1;
      this.lastShowIndex = -1;
    }
  
    // 更新曝光数据列表
    updateExpostListData(list) {
      this.exposeListData = list;
    }
  
    // 新增曝光数据列表
    addExposeListData(list) {
      this.exposeListData = this.exposeListData.concat(list);
    }
  
    // 获取可见区域边界
    getBoxBounding() {
      if (this.$boundaryElement && typeof this.$boundaryElement.getBoundingClientRect === 'function') {
        const { left, top, bottom, right } = this.$boundaryElement.getBoundingClientRect();
        return {
          left: Math.max(0, left),
          top: Math.max(0, top),
          bottom: Math.min(window.innerHeight, bottom),
          right: Math.min(window.innerWidth, right)
        };
      }
      // window box
      return { left: 0, top: 0, bottom: window.innerHeight, right: window.innerWidth };
    }
  
    // 检测是否可见
    checkInView(el, box) {
      const rect = el.getBoundingClientRect();
      const isVisible = el.style.display !== 'none';
      // 确定元素可见的范围：
      const isInView =
        rect.top + 2 >= box.top &&
        rect.bottom - 8 <= box.bottom &&
        rect.left + 1 >= box.left &&
        rect.right - 5 <= box.right;
      const result = isVisible && isInView;
      return result;
    }
  
    // 检测列表内容可见范围
    checkListItemShowStatus() {
      if (!this.$parent || !this.$parent.children || !this.$parent.children.length) return;
      const box = this.getBoxBounding();
      const list = this.$parent.children;
      const { length } = list;
      // 如果是初次计算，从上往下查找
      if (this.firstShowIndex === -1 || this.lastShowIndex === -1) {
        for (let i = 0; i < length; i++) {
          const isInView = this.checkInView(list[i], box);
          if (isInView && this.firstShowIndex === -1) {
            this.firstShowIndex = i;
          }
          if (this.firstShowIndex !== -1 && !isInView) {
            this.lastShowIndex = i - 1;
            break;
          }
        }
        if (this.firstShowIndex !== -1 && this.lastShowIndex === -1 && this.checkInView(list[length - 1], box)) {
          this.lastShowIndex = length - 1;
        }
        // 异常检测
        if (this.firstShowIndex === -1 || this.lastShowIndex === -1 || this.firstShowIndex > this.lastShowIndex) {
          console.log('无可见元素');
        } else {
          console.log(this.firstShowIndex, this.lastShowIndex);
          this.markElementShowTimeInfo();
        }
        return;
      }
      // 计算新的可见元素范围
      // 基于上一次，查找第一个可见元素
      if (this.checkInView(list[this.firstShowIndex], box)) {
        // 如果当前元素可见，往前查找，直到找到不可见元素为止，并把最后一个可见元素作为新的第一个的可见元素
        let i = this.firstShowIndex - 1;
        while (i >= 0 && i < length && this.checkInView(list[i], box)) {
          this.firstShowIndex = i;
          i--;
        }
      } else {
        // 如果当前元素不可见，往后查找，直到找到可见元素为止，并把查找到的可见元素做为新的第一个可见元素
        let i = this.firstShowIndex + 1;
        while (i >= 0 && i < length && !this.checkInView(list[i], box)) {
          i++;
        }
        // 向后查找如果没有找到可见元素
        if (i === length && !this.checkInView(list[this.firstShowIndex], box)) {
          console.log('查到第一个可见元素失败');
          this.firstShowIndex = -1;
        } else {
          this.firstShowIndex = i;
        }
      }
      // 基于上一次结果，查找最后一个可见元素
      if (this.checkInView(list[this.lastShowIndex], box)) {
        // 如果当前元素可见，往后查找，直到找到不可见元素为止，并把最后一个可见元素作为新的最后一个可见元素
        let i = this.lastShowIndex + 1;
        while (i < length && i >= 0 && i >= this.firstShowIndex && this.checkInView(list[i], box)) {
          this.lastShowIndex = i;
          i++;
        }
      } else {
        // 如果当前元素不可见，往前查找，直到找到可见元素为止，并把查找到的可见元素做为新的最后一个可见元素
        let i = this.lastShowIndex - 1;
        while (i < length && i >= 0 && i >= this.firstShowIndex && !this.checkInView(list[i], box)) {
          i--;
        }
        // 向前没有找到可见元素
        if (i === -1) {
          console.log('查找最后一个可见元素失败');
          this.lastShowIndex = -1;
        } else {
          this.lastShowIndex = i;
        }
      }
      if (this.firstShowIndex === -1 || this.lastShowIndex === -1) {
        this.markAllElementHide();
      } else if (this.firstShowIndex > this.lastShowIndex) {
        console.error('判断可见元素范围异常', this.firstShowIndex, this.lastShowIndex);
        this.markAllElementHide();
      } else {
        // console.log(this.firstShowIndex, this.lastShowIndex);
        this.markElementShowTimeInfo();
      }
    }
  
    // 标记曝光数据
    markElementShowTimeInfo() {
      const result = [];
      const len = this.exposeListData.length;
      const now = Date.now();
      for (let i = 0; i < len; i++) {
        const item = this.exposeListData[i];
        if (i >= this.firstShowIndex && i <= this.lastShowIndex) {
          // 在可见区域
          if (!item.showStartTime) {
            item.showStartTime = now;
          }
        } else if (item.showStartTime) {
          // 不在可见区域
          item.index = i;
          item.duration = ((now - item.showStartTime) / 1000).toFixed(3);
          delete item.showStartTime;
          result.push(item);
        }
      }
      if (result.length) {
        this.reportHander(this.eventId, this.eventDesc, result);
      }
    }
  
    // 标记所有内容均隐藏
    markAllElementHide() {
      const result = [];
      const now = Date.now();
      for (let i = 0; i < this.exposeListData.length; i++) {
        const item = this.exposeListData[i];
        if (item.showStartTime) {
          item.index = i;
          item.duration = ((now - item.showStartTime) / 1000).toFixed(3);
          delete item.showStartTime;
          result.push(item);
        }
      }
      if (result.length) {
        this.reportHander(this.eventId, this.eventDesc, result);
      }
    }
  }